package com.example.utility.crypto.ecc;


import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @author 季舟
 * @Date 2024-12-23 13:07
 */
public class ECCEncryptionDemo {
    /**
     * 生成密钥对
     *
     * @param keySize 密钥长度
     * @return 密钥对
     */
    public static KeyPair generateKeyPair(int keySize) throws Exception {
        // 获取指定算法的密钥对生成器
        Security.addProvider(new BouncyCastleProvider());
        /**
         * 这段代码的功能是获取一个指定算法的密钥对生成器实例。具体来说：
         * 使用 KeyPairGenerator.getInstance("EC", "BC") 获取椭圆曲线（EC）算法的密钥对生成器。
         * 指定使用 BouncyCastle 提供者（"BC"）来生成密钥对。
         */
        final KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "BC");
        // 初始化密钥对生成器（指定密钥长度, 使用默认的安全随机数源）
        generator.initialize(keySize);
        // 随机生成一对密钥（包含公钥和私钥）
        return generator.generateKeyPair();
    }


    /**
     * ECC 加密
     *
     * @param publicKeyBytes 公钥
     * @param plain 原文
     * @return　密文
     */
    public static byte[] encrypt(byte[] publicKeyBytes, byte[] plain) throws Exception {
        // 创建EC密钥工厂实例，指定使用椭圆曲线算法（EC）和Bouncy Castle（BC）作为安全提供者。
        final KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");

        // 创建X.509编码的公钥规范
        final X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);

        // 生成公钥对象
        final PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

        /**
         * 这段代码的功能是创建一个基于ECIES（椭圆曲线集成加密方案）的加密器实例，并指定使用BC（Bouncy Castle）提供者。具体来说：
         * Cipher.getInstance("ECIES", "BC")：
         * 创建一个Cipher对象，指定算法为ECIES。
         * 使用Bouncy Castle（BC）作为安全提供者。
         */
        final Cipher cipher = Cipher.getInstance("ECIES", "BC");

        // 初始化加密器为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        // 执行加密操作并返回密文
        return cipher.doFinal(plain);
    }

    /**
     * ECC 解密
     *
     * @param privateKeyBytes 　私钥
     * @param encrypted 　密文
     * @return　原文
     */
    public static byte[] decrypt(byte[] privateKeyBytes, byte[] encrypted) throws Exception {
        // 获取EC算法的KeyFactory实例
        final KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");

        // 创建PKCS8编码的私钥规范
        final PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);

        // 生成私钥
        final PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

        // 获取ECIES算法的Cipher实例
        final Cipher cipher = Cipher.getInstance("ECIES", "BC");

        // 初始化Cipher为解密模式
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        // 执行解密操作并返回原文
        return cipher.doFinal(encrypted);
    }

    /**
     * 主程序入口
     * 本程序主要用于演示使用ECC加密解密的过程
     * 首先生成一对RSA密钥，然后使用公钥加密一段数据，最后使用私钥解密这段数据
     *
     * @param args 命令行参数
     * @throws Exception 如果加密解密过程中发生错误
     */
    public static void main(String[] args) throws Exception {
        // 待加密的原始数据
        final String data = "12345678";
        System.out.println("原文:"+data);

        // 生成RSA密钥对
        final KeyPair keyPair = generateKeyPair(256);
        // 输出公钥和私钥，以便查看
        System.out.println("公钥:"+Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()));
        System.out.println("私钥:"+Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()));

        // 使用公钥加密原始数据
        final byte[] encrypted = encrypt(keyPair.getPublic().getEncoded(), data.getBytes());
        System.out.println("加密后的数据:"+Base64.getEncoder().encodeToString(encrypted));
        // 使用私钥解密数据
        final byte[] decrypted = decrypt(keyPair.getPrivate().getEncoded(), encrypted);
        System.out.println("解密后的数据:"+new String(decrypted));
    }
}
